package com.qf.util;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Vector;

/**
 * 封装操作数据库的工具类
 * @author 千锋健哥
 */
public class DBUtils {

    /**
     * java中专门为线程准备了一个集合对象, 一个线程就有一个自己的单独的ThreadLocal对象,
     * 由于线程之间是互相隔离的, ThreadLocal对象之间也是互相隔离的, 里面的数据互不影响.
     * 我们想要将A用户的连接对象和B用户的连接对象分开, 互相不影响, 所以可以用ThreadLocal来装连接对象
     */
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    //资源属性对象, 用来保存读取到的properties文件中的内容
    private static final Properties PROPERTIES = new Properties();

    /**
     * 加载驱动
     */
    static {
        try {
            //读取资源属性文件中的内容
            InputStream inputStream = DBUtils.class.getResourceAsStream("/db.properties");
            //将读取到的输入流, 传入Properties对象, 将内容保存到Properties对象中
            PROPERTIES.load(inputStream);
            //获取资源属性的内容并创建驱动
            Class.forName(PROPERTIES.getProperty("jdbc.driver"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取连接
     */
    public static Connection getConnection() {
        //1.从ThreadLocal中获取连接对象
        Connection connection = threadLocal.get();
        try {
            //2. 判断连接对象是否能够获取到
            if (connection == null) {
                /**
                 * 如果连接对象为空, 那么新建连接对象
                 * 从资源属性文件中获取数据库的url连接地址, 数据库用户名, 数据库密码
                 */
                String url = String.valueOf(PROPERTIES.get("jdbc.url"));
                String username = String.valueOf(PROPERTIES.get("jdbc.username"));
                String password = String.valueOf(PROPERTIES.get("jdbc.password"));
                connection = DriverManager.getConnection(url, username, password);
                //3. 将新建的连接对象放入ThreadLocal中保存, 下回直接使用就不用再次创建
                threadLocal.set(connection);
            }
            return connection;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 释放资源
     */
    public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                //关闭连接对象
                connection.close();
                //将连接对象从threadlocal中移除
                threadLocal.remove();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 开启事务
     */
    public static void beginTransaction() {
        //从threadlocal中获取连接
        Connection connection = getConnection();
        try {
            //开始事务并且关闭自动提交
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 提交事务
     */
    public static void commitTransaction() {
        //从threadlocal中获取连接
        Connection connection = getConnection();
        try {
            //提交事务
            connection.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            //不管事务执行成功还是失败都要最后关闭连接资源
            DBUtils.closeAll(connection, null, null);
        }
    }


    /**
     * 回滚事务
     */
    public static void rollbackTransaction() {
        //从threadlocal中获取连接
        Connection connection = getConnection();
        try {
            //事务回滚
            connection.rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            //不管事务执行成功还是失败都要最后关闭连接资源
            DBUtils.closeAll(connection, null, null);
        }
    }
}
